const t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
const e = String.fromCharCode
let n = {}

const _compress = (e, t, o) => {
    if (null == e)
        return "";
    var n, r, i, a = {}, s = {}, l = "", c = "", p = "", h = 2, u = 3, d = 2, f = [], g = 0, m = 0;
    for (i = 0; i < e.length; i += 1)
        if (l = e.charAt(i),
        Object.prototype.hasOwnProperty.call(a, l) || (a[l] = u++,
        s[l] = !0),
        c = p + l,
        Object.prototype.hasOwnProperty.call(a, c))
            p = c;
        else {
            if (Object.prototype.hasOwnProperty.call(s, p)) {
                if (p.charCodeAt(0) < 256) {
                    for (n = 0; n < d; n++)
                        g <<= 1,
                        m == t - 1 ? (m = 0,
                        f.push(o(g)),
                        g = 0) : m++;
                    for (r = p.charCodeAt(0),
                    n = 0; n < 8; n++)
                        g = g << 1 | 1 & r,
                        m == t - 1 ? (m = 0,
                        f.push(o(g)),
                        g = 0) : m++,
                        r >>= 1
                } else {
                    for (r = 1,
                    n = 0; n < d; n++)
                        g = g << 1 | r,
                        m == t - 1 ? (m = 0,
                        f.push(o(g)),
                        g = 0) : m++,
                        r = 0;
                    for (r = p.charCodeAt(0),
                    n = 0; n < 16; n++)
                        g = g << 1 | 1 & r,
                        m == t - 1 ? (m = 0,
                        f.push(o(g)),
                        g = 0) : m++,
                        r >>= 1
                }
                0 == --h && (h = Math.pow(2, d),
                d++),
                delete s[p]
            } else
                for (r = a[p],
                n = 0; n < d; n++)
                    g = g << 1 | 1 & r,
                    m == t - 1 ? (m = 0,
                    f.push(o(g)),
                    g = 0) : m++,
                    r >>= 1;
            0 == --h && (h = Math.pow(2, d),
            d++),
            a[c] = u++,
            p = String(l)
        }
    if ("" !== p) {
        if (Object.prototype.hasOwnProperty.call(s, p)) {
            if (p.charCodeAt(0) < 256) {
                for (n = 0; n < d; n++)
                    g <<= 1,
                    m == t - 1 ? (m = 0,
                    f.push(o(g)),
                    g = 0) : m++;
                for (r = p.charCodeAt(0),
                n = 0; n < 8; n++)
                    g = g << 1 | 1 & r,
                    m == t - 1 ? (m = 0,
                    f.push(o(g)),
                    g = 0) : m++,
                    r >>= 1
            } else {
                for (r = 1,
                n = 0; n < d; n++)
                    g = g << 1 | r,
                    m == t - 1 ? (m = 0,
                    f.push(o(g)),
                    g = 0) : m++,
                    r = 0;
                for (r = p.charCodeAt(0),
                n = 0; n < 16; n++)
                    g = g << 1 | 1 & r,
                    m == t - 1 ? (m = 0,
                    f.push(o(g)),
                    g = 0) : m++,
                    r >>= 1
            }
            0 == --h && (h = Math.pow(2, d),
            d++),
            delete s[p]
        } else
            for (r = a[p],
            n = 0; n < d; n++)
                g = g << 1 | 1 & r,
                m == t - 1 ? (m = 0,
                f.push(o(g)),
                g = 0) : m++,
                r >>= 1;
        0 == --h && (h = Math.pow(2, d),
        d++)
    }
    for (r = 2,
    n = 0; n < d; n++)
        g = g << 1 | 1 & r,
        m == t - 1 ? (m = 0,
        f.push(o(g)),
        g = 0) : m++,
        r >>= 1;
    for (; ; ) {
        if (g <<= 1,
        m == t - 1) {
            f.push(o(g));
            break
        }
        m++
    }
    return f.join("")
}

const _decompress = (t, o, n) => {
    var r, i, a, s, l, c, p, h = [], u = 4, d = 4, f = 3, g = "", m = [], y = {
        val: n(0),
        position: o,
        index: 1
    };
    for (r = 0; r < 3; r += 1)
        h[r] = r;
    for (a = 0,
    l = Math.pow(2, 2),
    c = 1; c != l; )
        s = y.val & y.position,
        y.position >>= 1,
        0 == y.position && (y.position = o,
        y.val = n(y.index++)),
        a |= (s > 0 ? 1 : 0) * c,
        c <<= 1;
    switch (a) {
    case 0:
        for (a = 0,
        l = Math.pow(2, 8),
        c = 1; c != l; )
            s = y.val & y.position,
            y.position >>= 1,
            0 == y.position && (y.position = o,
            y.val = n(y.index++)),
            a |= (s > 0 ? 1 : 0) * c,
            c <<= 1;
        p = e(a);
        break;
    case 1:
        for (a = 0,
        l = Math.pow(2, 16),
        c = 1; c != l; )
            s = y.val & y.position,
            y.position >>= 1,
            0 == y.position && (y.position = o,
            y.val = n(y.index++)),
            a |= (s > 0 ? 1 : 0) * c,
            c <<= 1;
        p = e(a);
        break;
    case 2:
        return ""
    }
    for (h[3] = p,
    i = p,
    m.push(p); ; ) {
        if (y.index > t)
            return "";
        for (a = 0,
        l = Math.pow(2, f),
        c = 1; c != l; )
            s = y.val & y.position,
            y.position >>= 1,
            0 == y.position && (y.position = o,
            y.val = n(y.index++)),
            a |= (s > 0 ? 1 : 0) * c,
            c <<= 1;
        switch (p = a) {
        case 0:
            for (a = 0,
            l = Math.pow(2, 8),
            c = 1; c != l; )
                s = y.val & y.position,
                y.position >>= 1,
                0 == y.position && (y.position = o,
                y.val = n(y.index++)),
                a |= (s > 0 ? 1 : 0) * c,
                c <<= 1;
            h[d++] = e(a),
            p = d - 1,
            u--;
            break;
        case 1:
            for (a = 0,
            l = Math.pow(2, 16),
            c = 1; c != l; )
                s = y.val & y.position,
                y.position >>= 1,
                0 == y.position && (y.position = o,
                y.val = n(y.index++)),
                a |= (s > 0 ? 1 : 0) * c,
                c <<= 1;
            h[d++] = e(a),
            p = d - 1,
            u--;
            break;
        case 2:
            return m.join("")
        }
        if (0 == u && (u = Math.pow(2, f),
        f++),
        h[p])
            g = h[p];
        else {
            if (p !== d)
                return null;
            g = i + i.charAt(0)
        }
        m.push(g),
        h[d++] = i + g.charAt(0),
        i = g,
        0 == --u && (u = Math.pow(2, f),
        f++)
    }
}

const r = (e, t) => {
    if (!n[e]) {
        n[e] = {};
        for (var o = 0; o < e.length; o++)
            n[e][e.charAt(o)] = o
    }
    return n[e][t]
}

const compressToBase64 = (e) => {
    if (null == e)
        return "";
    var o = _compress(e, 6, function(e) {
        return t.charAt(e)
    });
    switch (o.length % 4) {
        default:
        case 0:
            return o;
        case 1:
            return o + "===";
        case 2:
            return o + "==";
        case 3:
            return o + "="
    }
}

const decompressFromBase64 = (e) => {
    return null == e ? "" : "" == e ? null : _decompress(e.length, 32, function(o) {
        return r(t, e.charAt(o))
    })
}

module.exports = {
    compressToBase64,
    decompressFromBase64
}